package com.infra.micro.oss.domain.service.impl;

import com.alibaba.fastjson2.JSON;
import com.infra.common.resp.KeyValue;
import com.infra.common.resp.Response;
import com.infra.micro.oss.domain.client.OssClient;
import com.infra.micro.oss.domain.config.OssConfig;
import com.infra.micro.oss.domain.db.entity.BizInfoPO;
import com.infra.micro.oss.domain.db.entity.FileInfoPO;
import com.infra.micro.oss.domain.model.dto.ThumbnailDTO;
import com.infra.micro.oss.domain.repository.BizInfoRepository;
import com.infra.micro.oss.domain.repository.FileInfoRepository;
import com.infra.micro.oss.model.vo.BizFileVO;
import com.infra.micro.oss.model.vo.FileInfoVO;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public abstract class BaseFileService {
    public static final Logger LOGGER = LoggerFactory.getLogger(BaseFileService.class);
    public static final String THUMBNAIL_FORMAT_KEY = "%swh%s";
    @Resource
    public FileInfoRepository fileInfoRepository;
    @Resource
    public BizInfoRepository bizInfoRepository;
    @Resource
    public OssClient ossClient;
    @Resource
    private OssConfig ossConfig;

    public List<ThumbnailDTO> getThumbnailList(List<String> thumbnail) {
        if (CollectionUtils.isEmpty(thumbnail)) {
            return new ArrayList<>();
        }

        return thumbnail.stream()
                .map(item -> StringUtils.split(item, "*"))
                .filter(size -> size.length > 1 && StringUtils.isNumeric(size[0]) && StringUtils.isNumeric(size[1]))
                .map(size -> new ThumbnailDTO(Integer.valueOf(size[0]), Integer.valueOf(size[1])))
                .collect(Collectors.toList());
    }

    public void writeOutputStream(InputStream inputStream, HttpServletResponse response) throws IOException {
        byte[] buffer = new byte[10240];
        try (OutputStream output = response.getOutputStream()) {
            for (int length = 0; (length = inputStream.read(buffer)) > 0; ) {
                output.write(buffer, 0, length);
            }
        }
    }

    public void writeZipOutputStream(List<KeyValue> list, HttpServletResponse response) throws IOException {
        if (!CollectionUtils.isEmpty(list)) {
            try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
                for (KeyValue item : list) {
                    zos.putNextEntry(new ZipEntry(item.getText()));
                    InputStream inputStream = ossClient.getFileObject(item.getId());

                    byte[] buffer = new byte[10240];
                    for (int length = 0; (length = inputStream.read(buffer)) > 0; ) {
                        zos.write(buffer, 0, length);
                    }
                }
                zos.flush();
            }
        }
    }

    public InputStream thumbnail(final MultipartFile file, int width, int height) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        Thumbnails.of(file.getInputStream())
                .size(width, height) //缩略图尺寸大小
                //.sourceRegion(Positions.CENTER, width, height) //裁剪
                //.rotate(90)
                //.outputQuality(0.8f)
                //.keepAspectRatio(false)
                //.outputFormatType(MimeTypeEnum.getByMessage(file.getContentType()).getValue())
                .toOutputStream(byteArrayOutputStream);

        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }

    public FileInfoPO buildFileInfoPO(MultipartFile mpf, String sha, String md5) {
        FileInfoPO result = new FileInfoPO();

        result.setSize(mpf.getSize());
        result.setMimeType(mpf.getContentType());
        result.setSha(sha);
        result.setMd5(md5);
        result.setCreateTime(new Date());

        return result;
    }

    public BizFileVO buildBizFileVO(FileInfoPO fileInfoPO, String fileName) {
        BizFileVO result = new BizFileVO();
        BeanUtils.copyProperties(fileInfoPO, result);
        result.setFileName(fileName);

        return result;
    }

    public BizFileVO buildBizFileVO(BizInfoPO bizInfoPO, FileInfoPO fileInfoPO) {
        BizFileVO result = new BizFileVO();
        BeanUtils.copyProperties(fileInfoPO, result);
        if (fileInfoPO != null) {
            BeanUtils.copyProperties(bizInfoPO, result);
        }

        return result;
    }

    public FileInfoVO buildFileInfoVO(FileInfoPO fileInfoPO) {
        FileInfoVO record = new FileInfoVO();
        BeanUtils.copyProperties(fileInfoPO, record);
        return record;
    }

    public List<FileInfoVO> buildFileInfoVOs(List<FileInfoPO> list) {
        List<FileInfoVO> result = new ArrayList<>(CollectionUtils.isEmpty(list) ? 16 : list.size());
        if (!CollectionUtils.isEmpty(list)) {
            list.forEach(item -> result.add(buildFileInfoVO(item)));
        }
        return result;
    }

    public void rewrite404Response(HttpServletResponse httpServletResponse, Response response) throws IOException {
        httpServletResponse.reset();
        httpServletResponse.setStatus(HttpStatus.NOT_FOUND.value());
        httpServletResponse.setContentType("application/json");
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.getWriter().println(JSON.toJSONString(response));
    }
    public List<String> split(final String str, final String separatorChars) {
        if (StringUtils.isBlank(str)) {
            return new ArrayList<>();
        }
        return Arrays.stream(StringUtils.split(str, separatorChars)).distinct().collect(Collectors.toList());
    }

    public List<String> split(final String str, final String excludes, final String separatorChars) {
        List<String> result = split(str, separatorChars);
        List<String> exclusionList = split(excludes, separatorChars);
        return result.stream().filter(el -> !exclusionList.contains(el)).collect(Collectors.toList());
    }

    public List<String> merge(List<String> thumbnail1, List<String> thumbnail2) {
        List<String> result = new ArrayList<>();
        result.addAll(thumbnail1);
        result.addAll(thumbnail2);
        return result.stream().distinct().collect(Collectors.toList());
    }
}
